using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using BoOnce.Components;
using BoOnce.Core.Components;

namespace BoOnce.GameLogic.Entities
{
    abstract class Player : Somebody
    {
        #region Attributes
        private PlayerIndex _PlayerIndex;
        private PlayerActionComponent _PlayerActionComponent;
        #endregion

        #region Properties
        public PlayerIndex ControllerIndex { get { return _PlayerIndex; } }
        protected PlayerActionComponent PlayerActionComponent { get { return _PlayerActionComponent; } }
        #endregion

        #region Constructor
        public Player(PlayerIndex playerIndex, Vector2 pos, String name, float height, float width, float mass)
            : base(pos, name, height, width, mass)
        {
            _PlayerIndex = playerIndex;
            _PlayerActionComponent = (PlayerActionComponent)Game.Services.GetService(typeof(PlayerActionComponent));
            _PlayerActionComponent.AddPlayer(this);

            if (playerIndex == PlayerIndex.One) Camera.FollowedEntity = this;

            _PressedButtons = new LinkedList<ButtonAndTime>();
            _Combos = new List<Combo>();
        }
        #endregion


        #region Combo Detection management
        private class ButtonAndTime
        {
            public InputComponent.Buttons Button;
            public Double Time;

            public ButtonAndTime(InputComponent.Buttons b, Double t)
            {
                Button = b;
                Time = t;
            }
        }

        private int MAX_BUTTON_BUFFER = 10;
        private int DURATION_BEFORE_CLEANUP_BUTTON_BUFFER = 1500; //ms
        private LinkedList<ButtonAndTime> _PressedButtons;
        private List<Combo> _Combos;

#if DEBUG
        public List<String> GetPressedButtons()
        {
            List<String> list = new List<String>();
            foreach (ButtonAndTime b in _PressedButtons)
            {
                list.Add(b.Button.ToString());
            }
            return list;
        }

        public List<String> GetCombos()
        {
            List<String> list = new List<String>();
            foreach (Combo b in _Combos)
            {
                list.Add(b.ToString());
            }
            return list;
        }
#endif

        /// <summary>
        /// Check if a combo have been pressed, and return the pressed combo or null otherwise
        /// </summary>
        /// <returns>the pressed combo, or null otherwise</returns>
        protected Combo DetectCombo()
        {
            foreach (Combo combo in _Combos)
            {
                // if not enought buttons have been pressed; we skip the current combo
                if (_PressedButtons.Count < _Combos.Count) continue;

                // look if the current combo have been pressed
                LinkedList<ButtonAndTime>.Enumerator pressedButtonsEnum = _PressedButtons.GetEnumerator();
                foreach (InputComponent.Buttons button in combo.Description)
                {
                    if (pressedButtonsEnum.Current.Button != button) break;
                    if (!pressedButtonsEnum.MoveNext()) return combo;
                }
            }

            return null;
        }

        protected void Add(Combo combo)
        {
            _Combos.Add(combo);
        }

        private void CleanUpButtonBuffer(GameTime gameTime)
        {
            // remove buttons if the max size is raised
            while (_PressedButtons.Count > MAX_BUTTON_BUFFER) _PressedButtons.RemoveLast();

            // remove old pressed button
            while ((_PressedButtons.Count != 0) && ((_PressedButtons.Last.Value.Time + DURATION_BEFORE_CLEANUP_BUTTON_BUFFER) < gameTime.TotalGameTime.TotalMilliseconds)) _PressedButtons.RemoveLast();
        }

        protected void Add(InputComponent.Buttons pressedButton, GameTime gameTime)
        {
            _PressedButtons.AddFirst(new ButtonAndTime(pressedButton,gameTime.TotalGameTime.TotalMilliseconds));
        }
        #endregion

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
            CleanUpButtonBuffer(gameTime);
        }

#if DEBUG
        public override void QuickDraw(GameTime gameTime, Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
        {
            base.QuickDraw(gameTime, spriteBatch);
            float i = 0f;
            List<String> lines = GetPressedButtons();
            foreach (String line in lines)
            {
                DebugComponent.Print(spriteBatch, new Vector2(5 + i, 60), line);
                i += line.Length * 6.8f;
            }

            //i = 0f;
            //lines = GetCombos();
            //foreach (String line in lines)
            //{
            //    DebugComponent.Print(spriteBatch, new Vector2(5 + i, 70), line);
            //    i += line.Length * 6.8f;
            //}
        }
#endif

        #region overridable methods
        abstract public void ButtonHandler(InputComponent.Buttons buttons, GameTime gameTime, Boolean IsNew);
        #endregion
    }
}
